<?php
/**
 * Created by PhpStorm.
 * User: BlueIdeaLirui
 * Date: 2019/11/11
 * Time: 10:13
 */

namespace business\company\services\queues;

use business\base\caches\DataCache;
use business\base\services\SupplierTagsService;
use business\company\repositories\SupplierRepository;
use business\company\services\FhSupplierService;
use business\company\services\SelectionSupplierService;
use business\company\services\SupplierBoutiqueService;
use business\company\services\SupplierService;
use business\elasticsearch\models\PlatformSupplierModel;
use business\elasticsearch\repositories\IntegrateSupplierRepository;
use business\company\models\SupplierBasicModel;
use business\elasticsearch\models\IntegrateSupplierModel;
use business\search\services\SearchPriorityCategoryService;
use common\queue\QueueConstants;
use common\utils\DateTimeUtils;
use yii\helpers\ArrayHelper;

class SupplierConsumerService extends BaseService
{
    /**
     * 指定模块
     */
    const MODULE = 'supplier';
    private $searchPriorityCategory;

    /**
     * 供应商消费端服务构造器
     * SupplierConsumerService constructor.
     */
    public function __construct()
    {
        $this->createIndex();
        $this->searchPriorityCategory = new SearchPriorityCategoryService();
        parent::__construct();
    }

    /**
     * 创建索引
     */
    protected function createIndex()
    {
        echo "\ncreateIndex running...\n";
        $repository = new IntegrateSupplierRepository();
        !$repository->existsIndex() && $repository->createIndex();
        echo "\ncreateIndex done...\n";

    }

    /**
     * 消费端实现
     * @throws \yii\base\InvalidConfigException
     */
    public function process
    (
        $values,
        $key,
        $messageId
    ) {
        $this->consumeQueue($this->callbackMethod, $values, $key, $messageId);
    }

    /**
     * 消费队列
     * @param callable $sucessedCallback
     * @return bool|mixed
     * @throws \yii\base\InvalidConfigException
     */
    protected function consumeQueue
    (
        callable $sucessedCallback,
        $values = '',
        $key = '',
        $messageId
    ) {
        echo "\nconsumeQueue running...\n";

        $needUpdateIndexSuppliers = [];
        $needDeleteIndexSuppliers = [];

        $supplierRepository = new SupplierRepository();
        $dataCache          = new DataCache();

        $queueCacheName     = self::MODULE . '-' . QueueConstants::QUEUE_CHACHE_NAME;

        if ($dataCache->existsValue('consumer-' . $queueCacheName . ':' . $key
                , serialize(['values' => $values, 'created_on' => DateTimeUtils::now()])) == 1) {
            // 清除缓存记录
            $dataCache->delRecordByHash($queueCacheName, $key);

            $waitUpdateSupplierIds = explode(self::DELIMITER, $values);

            if (!empty($waitUpdateSupplierIds)) {
                $start = 0;
                $sizeCount = (self::MAX_COUNT_PER_INDEX / self::MAX_COUNT_PER_QUERY);

                while (1) {
                    $start++;

                    $startTime = explode(' ', microtime());

                    $slicceUpdateSupplierIds = array_slice($waitUpdateSupplierIds, ($start - 1) * $sizeCount, $sizeCount);

                    if (!empty($slicceUpdateSupplierIds)) {
                        $supplierBasics = $supplierRepository->getSupplierBasicInfoByIds($slicceUpdateSupplierIds);
                        if (is_array($supplierBasics)) {
                            $basicIds = array_column($supplierBasics, 'supplier_id');
                            // 判断是否有删除的供应商数据
                            foreach ($slicceUpdateSupplierIds as $id) {
                                if (!in_array($id, $basicIds)) {
                                    array_push($needDeleteIndexSuppliers, $id);
                                }
                            }
                        }
                        $this->getSupplierDocumentArray($supplierBasics, $needUpdateIndexSuppliers, $needDeleteIndexSuppliers);
                        $endTime = explode(' ', microtime());
                        $thisTime = $endTime[0] + $endTime[1] - ($startTime[0] + $startTime[1]);
                        echo "平台供应商-增量索引更新：每" . $sizeCount . "条记录执行数据拼接耗时：" . round($thisTime, 3) . " 秒" . PHP_EOL;

                        //每x次轮训刷新一次搜索引擎
                        if ($start % $sizeCount == 0
                            && (!empty($needUpdateIndexSuppliers) || !empty($needDeleteIndexSuppliers))
                        ) {
                            //刷新搜索引擎
                            $this->updateDataIndex($needUpdateIndexSuppliers, 'update');
                            $this->updateDataIndex($needDeleteIndexSuppliers, 'delete');

                            $needUpdateIndexSuppliers = [];
                            $needDeleteIndexSuppliers = [];
                        }
                    } else {
                        // 清除缓存记录
                        $dataCache->delRecordByHash($queueCacheName, $key);
                        break;
                    }
                }
            }

            // 防止最后的未更新
            $this->updateDataIndex($needUpdateIndexSuppliers, 'update');
            $this->updateDataIndex($needDeleteIndexSuppliers, 'delete');

            // 清除缓存记录
            $dataCache->delRecordByHash($queueCacheName, $key);

            if (is_callable($sucessedCallback)) {
                return call_user_func($sucessedCallback, $needUpdateIndexSuppliers);
            }

            return true;
        }

        return true;
    }

    /**
     * 返回供应商文档
     * @param $supplierBasics
     * @param $needUpdateIndexSuppliers
     * @param array $needDeleteIndexSuppliers
     */
    public function getSupplierDocumentArray
    (
        $supplierBasics,
        & $needUpdateIndexSuppliers,
        & $needDeleteIndexSuppliers = []
    ) {
        if (!empty($supplierBasics)) {
            foreach ($supplierBasics as $basic) {
                $supplierId   = $basic['supplier_id'];
                $supplierInfo = $this->getDetailSupplierInfo($supplierId);
                //校验条件
                $checkResult = $this->checkConstructIndexCondition($supplierId, $supplierInfo);
                if (!$checkResult['success']) {
                    array_push($needDeleteIndexSuppliers, $supplierId);
                } else {
                    array_push($needUpdateIndexSuppliers, $supplierInfo);
                }
            }
        }
    }

    /**
     * 检查索引构建的条件
     * @param $supplierId
     * @param $supplierInfo
     * @return array
     */
    protected function checkConstructIndexCondition($supplierId, $supplierInfo)
    {
        $result = [
            'success' => true,
            'errMsg' => ''
        ];

        //供应商id为空
        if ($result['success'] && empty($supplierId)) {
            $result['errMsg'] = '供应商id为空，此条数据不会导入搜索引擎！';
            $result['success'] = false;
        }
        //供应商为测试数据(以test开头则为测试数据)
        if ($result['success'] && (!isset($supplierInfo['companyName']) || !strncmp($supplierInfo['companyName'],
                    'test', 4))
        ) {
            $result['errMsg'] = "此供应商($supplierId)为测试数据，数据不会导入搜索引擎！";
            $result['success'] = false;
        }
        // 历史原因
        if ($result['success'] && in_array($supplierId,[
                'G202875','G202881','G193866','G207971','G211151',
                'G229103','G193804','G192875','G192825','G211952',
                'G192914','G207978','G221882','G232604','G235523','G190816',
                'G224556','G197698','G197849','G190812','G206394','G205535',
                'G205542','G206727','G220428','G224322','G227229','G227340',
                'G192867','G213696','G189669','G203430','G224582','G220428'
            ])) {
            $result['errMsg'] = "此供应商($supplierId)为历史数据（通过非正规渠道导入），数据不会导入搜索引擎！";
            $result['success'] = false;
        }
        //供应商基础分类为空
//        if ($result['success'] && (!isset($supplierInfo['basicCategoryCode']) || empty($supplierInfo['basicCategoryCode']))) {
//            $result['errMsg'] = "此供应商($supplierId)没有基础分类，数据不会导入搜索引擎！";
//            $result['success'] = false;
//        }
        //供应商未通过审核或已冻结不进入搜索引擎
        if ($result['success'] && ($supplierInfo['state']!=2 || $supplierInfo['status']!=2)) {
            $result['errMsg'] = "此供应商($supplierId)没有未通过审核或已冻结，数据不会导入搜索引擎！";
            $result['success'] = false;
        }
        //非合规性数据持久化
        if (!$result['success']) {
            $title = isset($supplierInfo['companyName']) ? $supplierInfo['companyName'] : '';
            $this->saveUnIndexData('es_supplier', $title, $supplierId, $result['errMsg']);
        }

        return $result;
    }

    /**
     * 返回供应商等级
     * @param string $diamond
     * @param string $platinum
     * @param string $gold
     * @param array $user
     * @return int|mixed
     */
    protected function getSupplierLevel
    (
        $diamond = '',
        $platinum = '',
        $gold = '',
        $regionalDiamond = '',
        $user = []
    ) {
        $levels = array_filter(
            [
                ($diamond  == 1 ? 1 : ''),
                ($platinum == 1 ? 2 : ''),
                ($regionalDiamond == 1 ? 5 : ''),       //添加区域钻石
                ($gold     == 1 ? 3 : ''),
                (count($user) > 0 ? 4 : '')
            ]
        );
        return !empty($levels) ? current($levels) : 0;
    }

    /**
     * 返回是否为此标签类型
     * @param array $tags
     */
    protected function getIsTagsType($tags = [], $type = 2)
    {
        if (!empty($tags)) {
            if (in_array($type, $tags)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 返回认证用户等级
     * @param $user
     */
    protected function getUserLevel($user)
    {
        $userCount = count($user);

        if ($userCount >= 1 && $userCount <= 5) {
            return 1;
        } else if ($userCount >= 6 && $userCount <= 10) {
            return 2;
        } else if ($userCount > 10) {
            return 3;
        } else {
            return 0;
        }

        return 0;
    }

    /**
     * 返回注册资本等级
     * @param $regCapital
     */
    protected function getRegisteredCapitaLevel($regCapital)
    {
        if ($regCapital >= 1000 && $regCapital <= 3000) {
            return 1;
        } else if ($regCapital > 3000 && $regCapital <= 5000) {
            return 2;
        } else if ($regCapital > 5000) {
            return 3;
        } else {
            return 0;
        }

        return 0;
    }

    /**
     * 返回开发商推荐等级
     * @param $recommendCount
     */
    protected function getRecommendLevel($recommendCount)
    {
        if ($recommendCount >= 1 && $recommendCount <= 10) {
            return 1;
        } else if ($recommendCount > 10 && $recommendCount <= 20) {
            return 2;
        } else if ($recommendCount > 20 && $recommendCount <= 50) {
            return 3;
        } else if ($recommendCount > 50) {
            return 4;
        } else {
            return 0;
        }

        return 0;
    }

    /**
     * 返回入库等级
     * @param $inStorageCount
     */
    protected function getStorageLevel($inStorageCount)
    {
        if ($inStorageCount >= 1 && $inStorageCount <= 10) {
            return 1;
        } else if ($inStorageCount > 10 && $inStorageCount <= 20) {
            return 2;
        } else if ($inStorageCount > 20 && $inStorageCount <= 50) {
            return 3;
        } else if ($inStorageCount > 50) {
            return 4;
        } else {
            return 0;
        }

        return 0;
    }

    /**
     * 获取供应商详细信息
     * @param $supplier_id
     * @return array
     */
    protected function getDetailSupplierInfo($supplier_id)
    {
        $supplierService = new SupplierService();

        $supplierTagsService = new SupplierTagsService();

        $selectionSupplierService = new SelectionSupplierService();

        $fhService = new FhSupplierService();

        //获取基本信息
        $basicInfo = $supplierService->getSupplierBasicInfo($supplier_id);

        //获取服务分类
        $categoryInfo = $supplierService->getSupplierCategoryInfo($supplier_id);

        //获取服务资质信息
        $qualifiesInfo = $supplierService->getSupplierQualifies($supplier_id);

        //获取用户信息
        $userInfo = $supplierService->getSupplierUser($supplier_id);

        //行业Top级
        $industryTop = $supplierTagsService->getIndustryTopBySupplierId($supplier_id);

        //榜上有名
        $famousList = $supplierTagsService->getFamousListBySupplierId($supplier_id);

        // =====================百强合作单位（满足以下其一即可）===================== //
        //获取项目案例信息
        $projectInfo = $supplierService->getSupplierProjects($supplier_id);

        //获取中标信息
        $biddingInfo = $supplierService->getSupplierAwardBidding($supplier_id);

        //获取战略合作信息
        $strategyInfo = $supplierTagsService->getHundredStrategyBySupplierId($supplier_id);
        // =====================百强合作单位（满足以下其一即可）===================== //

        //获取产品信息
        $productInfo = $supplierService->getSupplierProducts($supplier_id);

        //获取排序信息
        $sortInfo = $supplierService->getSupplierSortInfo($supplier_id, $basicInfo);

        //获取其他信息
        $otherInfo = $supplierService->getSupplierOtherInfo($supplier_id);

        //获取被推荐数
        $recommendCount = (int)$supplierService->getSupplierRecommend($supplier_id);

        //获取被入库数
        $inStorageCount = (int)$supplierService->getSupplierInStorage($supplier_id);

        //返回公司旗下联系人数量
        $contactsCount = (int)$supplierService->getContactsCountBySupplierId($supplier_id, $basicInfo);

        // 获取2020峰会榜单
        $voteInfo = $supplierService->getSupplierVoteInfo($supplier_id);

        //获取行业数据
        $industryData = $supplierService->getIndustryData($basicInfo['regLocationCode'], $basicInfo['regLocationCity'], $basicInfo['companyName']);

        //获取报名招募的数据
        $recruitData = $supplierService->getSupplierRegRecruitInfo($supplier_id);

        // 是否精选供应商
        $isSelection = $selectionSupplierService->IsBoutique($supplier_id);
        // 获取战略数量
        $strategicCaseNum = $selectionSupplierService->getStrategicCaseNum($supplier_id);
        // 获取营业额
        $turnoverNum = $selectionSupplierService->getSupplierRevenue($supplier_id);
        // 获取上市类型
        $listedType = $basicInfo['listedType'];
        //is_high_tech,is_special_new,little_giants,enterprise_technology_center
        $fhSupplierDetail = $fhService->getSupplierDetail($supplier_id);
        // 高新企业
        $isHighTech = $fhSupplierDetail['is_high_tech'];
        // 高新特精
        $isSpecialNew = $fhSupplierDetail['is_special_new'];
        // 小巨人
        $isLittleGiants = $fhSupplierDetail['little_giants'];
        // 绿建产品
        $greenProductNum = $selectionSupplierService->getSupplierGreenProductNum($supplier_id);
        // 技术中心
        $enterpriseTechnologyCenter = $fhSupplierDetail['enterprise_technology_center'];

//        $tagType = $supplierTagsService->getSupplierTagsById($supplier_id, 'tag_type')['tag_type'];

        // 供应商标签项
        $supplierTags = [];
        $res = $supplierTagsService->getYoucaiHundredSupplierData($supplier_id, 'uid');
        if (isset($res['uid']) && $res['uid']) {
            $supplierTags = ['3']; // 百强战略标签
        }

        //峰会榜单扩展标签 12=>峰会榜单 13=>高品质榜单
        // 14-精选；15-高新技术企业；16-专精特新企业；17-小巨人；18-绿色产品；19-企业技术中心
        if ($voteInfo['isTop10For2020'] == 1) {
            array_push($supplierTags,'12');
        }
        if ($voteInfo['isHighQualityFor2020'] == 1) {
            array_push($supplierTags,'13');
        }
        if ($isSelection) {
            array_push($supplierTags,'14');
        }
        if ($isHighTech) {
            array_push($supplierTags,'15');
        }
        if ($isSpecialNew) {
            array_push($supplierTags,'16');
        }
        if ($isLittleGiants) {
            array_push($supplierTags,'17');
        }
        if ($greenProductNum > 0) {
            array_push($supplierTags,'18');
        }
        if ($enterpriseTechnologyCenter > 0) {
            array_push($supplierTags,'19');
        }
        $rtnContractedAmount = $supplierTagsService->getContractedAmount($supplier_id);

        $contractedAmount = isset($rtnContractedAmount['amount']) && !empty($rtnContractedAmount['amount']) ? (float) $rtnContractedAmount['amount'] : 0;

        $users = !empty($userInfo['userJSON']) ? json_decode($userInfo['userJSON'], true) : [];

        $mainBusiness = $this->searchPriorityCategory->getPriorityCategoryBySupplierId($supplier_id);
        if (empty($mainBusiness) && !empty($categoryInfo['basicCategoryCode'])) {
            $mainBusiness = $categoryInfo['basicCategoryCode'];
        }
        return array_merge(
            $basicInfo,
            $categoryInfo,
            $qualifiesInfo,
            $userInfo,
            $projectInfo,
            $biddingInfo,
            $recruitData,
            $productInfo,
            $sortInfo,
            $otherInfo,
            $industryData,
            $voteInfo,
            [
                'recommendCount' => $recommendCount,
                'inStorageCount' => $inStorageCount,
                'linkNumber' => $contactsCount,
                'industryTop' => $industryTop,
                'famousList' => $famousList,
                'strategyInfo' => ArrayHelper::getColumn($strategyInfo, 'developer_name'),
                'supplierTags' => $supplierTags,
                'supplierLevel' => $this->getSupplierLevel(
                    $basicInfo['isDiamondSupplier'],
                    $basicInfo['isPlatinumSupplier'],
                    $basicInfo['isGoldenSupplier'],
                    $basicInfo['isRegionalDiamond'],
                    $users
                ),
                'isTop10Competitiveness' => $this->getIsTagsType($supplierTags, 2),
                'isIndustryTop' => $this->getIsTagsType($supplierTags, 1),
                'isTop100StrategicCooperation' => $this->getIsTagsType($supplierTags, 3),
                'userLevel' => $this->getUserLevel($users),
                'registeredCapitaLevel' => $this->getRegisteredCapitaLevel($basicInfo['regCapital']),
                'recommendLevel' => $this->getRecommendLevel($recommendCount),
                'storageLevel' => $this->getStorageLevel($inStorageCount),
                'contractedAmount' => $contractedAmount,
                'mainBusiness' => $mainBusiness,
                'isBoutique' => $isSelection,
                'strategicCaseNum' => $strategicCaseNum,
                'turnoverNum' => $turnoverNum,
                'listedType' => $listedType,
                'topTenCategory' => $voteInfo['topTenCategory'] ?? ''
            ]
        );
    }

    /**
     * 处理需要更新的平台供应商数据
     * @param $needUpdateIndex
     * @param $repository \business\bigdata\repositories\SupplierRepository
     * @return array
     */
    protected function handleUpdateSet
    (
        $needUpdateIndex,
        $repository
    ) {
        $updateIndex = [];

        if (!empty($needUpdateIndex)) {
//            $supplierBasicInfo = $repository->getSupplierBasicInfoByCompanyName($needUpdateIndex['companyName']);
//            if (!empty($supplierBasicInfo)) {
//                $supplierId = $supplierBasicInfo['id'];
//                $updateIndex['bigdataSupplierId'] = $supplierId;
//            } else {
//                $updateIndex['bigdataSupplierId'] = '';
//            }
            // 工商信息（字段优先取平台，为空取大数据）- 平台没有工商信息，直接获取大数据字段
            // 服务资质（取平台）
            // 企业证照（仅取平台）
            // 百强战略合作（仅取平台）
            // 成功案例（仅取平台）
            // 中标案例（仅取平台）
            // 云采购大数据（仅取大数据）
            // 开发商入库（仅取平台）
            // 开发商推荐（仅取平台）
            // 产品服务（仅取平台）
            // 企业联系人（仅取平台）
            // 企业联系方式（仅取平台）
            // 供应商百强标签（仅取大数据）------------（大数据字段）
            // 榜上有名（仅取平台，平台十强标签）

            // 当provinceCode，cityCode = "china"，转换成0，解决ES该字段为long类型的写入报错
            if ($needUpdateIndex['provinceCode'] == "china") {
                $needUpdateIndex['provinceCode'] = 0;
            }
            if ($needUpdateIndex['cityCode'] == "china") {
                $needUpdateIndex['cityCode'] = 0;
            }
            $updateIndex = $needUpdateIndex;
        }

        return $updateIndex;
    }

    /**
     * 更新索引
     * @param array $needUpdateIndexArrays
     * @param $jobCreatedTime
     */
    public function updateIndex
    (
        $needUpdateIndexArrays = [],
        $jobCreatedTime
    ) {
        if (!empty($needUpdateIndexArrays)) {
            $indexStartTime = explode(' ', microtime());

            $repository = new \business\bigdata\repositories\SupplierRepository();

            foreach ($needUpdateIndexArrays as $needUpdateIndex) {
                //$supplierId  = $needUpdateIndex['companySupplierId'];
                $supplierId  = $needUpdateIndex['supplierId'];
                $companyName = $needUpdateIndex['companyName'];

                $id = md5($companyName);

                try {
                    //$supplierEsModel = IntegrateSupplierModel::findOne($id);
                    $supplierEsModel = PlatformSupplierModel::getOneBySupplierId($supplierId);
                    if (empty($supplierEsModel)) {
                        //$supplierEsModel = new IntegrateSupplierModel();
                        $supplierEsModel = new PlatformSupplierModel();
                        $supplierEsModel->primaryKey = $id;
                    }

                    $supplierEsModel->setAttributes($this->handleUpdateSet($needUpdateIndex, $repository), false);
                    $supplierEsModel->indexCreatedTime = !empty($jobCreatedTime)
                        ? $jobCreatedTime :date('Y-m-d H:i:s');
                    $rs = $supplierEsModel->save();
                    if (!$rs) {
                        \Yii::error('update es_supplier failed! supplier_id:' . $supplierId);
//                        echo "\n handle error supplier_id is " . $supplierId . PHP_EOL;
                    }

                    echo 'success supplier_id is ' . $supplierId . PHP_EOL;
                } catch (\Throwable $e) {
                    echo 'update failed! supplier_id:' . $supplierId . PHP_EOL;
                    var_dump($e->getMessage());
                    $title = isset($companyName) ? $companyName : '';
                    $this->saveUnIndexData('es_supplier', $title, $supplierId, $e);
                }

            }

            $indexEndTime = explode(' ', microtime());
            $indexThisTime = $indexEndTime[0] + $indexEndTime[1] - ($indexStartTime[0] + $indexStartTime[1]);
            $indexThisTime = round($indexThisTime, 3);
            echo  "update索引耗时：" . $indexThisTime . " 秒" . PHP_EOL;
        }
    }

    /**
     * 删除索引
     * @param array $needDeleteIndexArrays
     * @param $jobCreatedTime
     * @throws \yii\elasticsearch\Exception
     */
    public function deleteIndex
    (
        $needDeleteIndexArrays = [],
        $jobCreatedTime
    ) {
        if (!empty($needDeleteIndexArrays)) {
            $indexStartTime = explode(' ', microtime());

            foreach ($needDeleteIndexArrays as $supplierId) {
                $supplier = SupplierBasicModel::findOne(['supplier_id' => $supplierId]);

                $companyName = $supplier->companyName;

                $id = md5($companyName);

                try{
                    //$supplierEsModel = IntegrateSupplierModel::findOne($id);
                    //$supplierEsModel = PlatformSupplierModel::findOne($id);
                    $supplierEsModel = PlatformSupplierModel::getOneBySupplierId($supplierId);

                    if ($supplierEsModel) {
                        $rs = $supplierEsModel->deleteAll(['_id' => $supplierEsModel->primaryKey]);

                        if (!$rs) {
                            \Yii::error('delete es_supplier failed! supplier_id:' . $supplierId);
                        }
                        echo 'success supplier_id is ' . $supplierId . PHP_EOL;
                    }

                } catch (\Exception $e) {
                    echo 'delete failed! supplier_id:' . $supplierId . PHP_EOL;
                    $title = isset($companyName) ? $companyName : '';
                    $this->saveUnIndexData('es_supplier', $title, $supplierId, $e);
                }
            }

            $indexEndTime = explode(' ', microtime());
            $indexThisTime = $indexEndTime[0] + $indexEndTime[1] - ($indexStartTime[0] + $indexStartTime[1]);
            $indexThisTime = round($indexThisTime, 3);
            echo "  删除索引耗时：" . $indexThisTime . " 秒" . PHP_EOL;
        }
    }
}
